﻿using ComputerVision.ANN;
using ComputerVision.Common;
using Emgu.CV;
using Emgu.CV.Structure;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Threading;
using System.Windows.Forms;
using AxLIVEXLib;
using stdole;

namespace ComputerVision
{
    public partial class frmTrainningCharacter : Form
    {

        Capture _cap0;
        byte _cmr0;
        Image<Bgr, Byte> biensoxevao;
        string bienso;
        string strmucxam;
        double dblmucxam;
        System.Text.RegularExpressions.Regex regex;
        HaarCascade haarkytu;
        Common.ImageProcess process;
        //Neural Network Object With Output Type String
        private NeuralNetwork<string> neuralNetwork;

        //Data Members Required For Neural Network
        private Dictionary<string, double[]> TrainingSet;
        private int av_ImageHeight;
        private int av_ImageWidth;
        private int NumOfPatterns;

        //For Asynchronized Programming Instead of Handling Threads
        private delegate bool TrainingCallBack();
        private AsyncCallback asyCallBack;
        private IAsyncResult res;
        private ManualResetEvent ManualReset;

        private Bitmap imgS = null;

        public frmTrainningCharacter()
        {
            InitializeComponent();
            regex = new System.Text.RegularExpressions.Regex("\\d\\d-[A-Z][0-9A-Z]-\\d{4,5}");
            haarkytu = new HaarCascade(Application.StartupPath + "\\kytu.xml");
            process = new Common.ImageProcess();
            
            //axLiveX1.OnGetPicture += new AxLIVEXLib._DLiveXEvents_OnGetPictureEventHandler(axLiveX1_OnGetPicture);
        }

        void axLiveX1_OnGetPicture(object sender, AxLIVEXLib._DLiveXEvents_OnGetPictureEvent e)
        {
            //axLiveX1.StartGrapImage(false);
            //imgS = ImageProcess.ImageConvert.GetImageFromIPicture(e.mPict);
        }

        private void CaptureWc()
        {
            _cmr0 = 0;
            _cap0 = new Capture(_cmr0);
            _cap0.ImageGrabbed += wc0;
            _cap0.Start();
        }

        private void wc0(object sender, EventArgs e)
        {
            //imgVaoTruoc.Image = _cap0.RetrieveBgrFrame();
        }

        private void ANNForm_Load(object sender, EventArgs e)
        {
            //CaptureWc();
            //Save();
            //asyCallBack = TraningCompleted;
            //ManualReset = new ManualResetEvent(false);


            this.axLiveX1.IpAddress = "192.168.1.99";
            this.axLiveX1.CommandPort = System.Convert.ToInt32("4550");
            this.axLiveX1.DataPort = System.Convert.ToInt32("5550");
            this.axLiveX1.AudioDataPort = System.Convert.ToInt32("6550");
            this.axLiveX1.DisablePWD = true;
            this.axLiveX1.UserName = "admin";
            this.axLiveX1.Password = "123456";
            this.axLiveX1.PlayX();
        }

        private void TraningCompleted(IAsyncResult result)
        {
            if (result.AsyncState is TrainingCallBack)
            {
                var TR = (TrainingCallBack)result.AsyncState;

                bool isSuccess = TR.EndInvoke(res);
                if (isSuccess)
                    MessageBox.Show("Training Success.....");
                else
                    MessageBox.Show("Training Process is Aborted or Exceed Maximum Iteration\r\n");
            }
        }
        private void button1_Click(object sender, EventArgs e)
        {
            MessageBox.Show("Began Training Process..\r\n");
            ManualReset.Reset();
            var TR = new TrainingCallBack(neuralNetwork.Train);
            res = TR.BeginInvoke(asyCallBack, TR);
        }
        private void Save()
        {
            var Images = Directory.GetFiles(Application.StartupPath+@"\ImageTrainning", "*.bmp");
            NumOfPatterns = Images.Length;
            av_ImageHeight = 0;
            av_ImageWidth = 0;
            foreach (var s in Images)
            {
                var Temp = new Bitmap(s);
                av_ImageHeight += Temp.Height;
                av_ImageWidth += Temp.Width;
                Temp.Dispose();
            }
            av_ImageHeight /= NumOfPatterns;
            av_ImageWidth /= NumOfPatterns;

            int networkInput = av_ImageHeight * av_ImageWidth;
            GenerateTrainingSet();
            CreateNeuralNetwork();
        }

        private void CreateNeuralNetwork()
        {
            if (TrainingSet == null)
                throw new Exception("Unable to Create Neural Network As There is No Data to Train..");

            neuralNetwork = new NeuralNetwork<string>
                (new BP3Layer<string>(av_ImageHeight * av_ImageWidth, 295, 98, NumOfPatterns), TrainingSet);

            neuralNetwork.MaximumError = 1.1;
        }

        private void GenerateTrainingSet()
        {
            var Patterns = Directory.GetFiles(Application.StartupPath + @"\ImageTrainning", "*.bmp");
            TrainingSet = new Dictionary<string, double[]>(Patterns.Length);
            foreach (string s in Patterns)
            {
                var Temp = new Bitmap(s);
                TrainingSet.Add(Path.GetFileNameWithoutExtension(s),
                    ImageProcessing.ToMatrix(Temp, av_ImageHeight, av_ImageWidth));
                Temp.Dispose();
            }
        }

        private void button2_Click(object sender, EventArgs e)
        {
            if (Timer_Vao.Enabled == false)
            {
                //axLiveX1.StartGrapImage(true);
                Timer_Vao.Enabled = true;
                picBiensovao.Image = null;
            }
            else
            {
                //axLiveX1.StartGrapImage(false);
                Timer_Vao.Enabled = false;
                picBiensovao.Image = null;
            }
           
        }
        public string docbiensoForm(Image<Bgr, byte> img, PictureBox picbox)
        {
            //hàm trả về ký tự biển số và hiển thị ảnh biển số lên imgbox
            string bienso = "";
            var img2 = process.dinhviBienSo(img);
            if (img2 != null)
            {
                bienso = NhanDienKyTuFrom(img2);
                picbox.Image = img2.ToBitmap();
            }
            return bienso;
        }
        public string NhanDienKyTuFrom(Image<Bgr, byte> img)
        {
            //giai đoạn nhận diện ký tự gồm 3 bước:
            //Bước 1: sắp xếp các ký tự từ trái qua phải
            //Bước 2: chuyển ảnh ký tự thành tập dữ liệu SVM hợp lệ
            //Bước 3: nhận diện các tập dữ liệu và nối thành chuỗi kết quả
            var GrayImage = img.Convert<Gray, byte>();
            var kytu = GrayImage.DetectHaarCascade(haarkytu)[0];
            //ảnh các ký tự
            var imgkytu = new Image<Gray, Byte>[10];
            Image<Gray, Byte> Part1 = null;
            Image<Gray, Byte> Part2 = null;
            Image<Gray, Byte> Part3 = null;
            Image<Gray, Byte> Part4 = null;

            int p1 = 0;
            //lưu các toạ độ của khung chữ nhật chứa ký tự
            var toado = new int[10];
            //sắp xếp các ký tự từ trái qua phải, từ trên xuống dưới
            foreach (var det in kytu)
            {
                if (det.rect.Y < 65 || det.rect.Y > 165)
                {
                    if (det.rect.Y > 170)
                    {
                        imgkytu[p1] = GrayImage.Copy(det.rect).Resize(20, 48, Emgu.CV.CvEnum.INTER.CV_INTER_LINEAR);
                        toado[p1] = det.rect.X;

                        for (int k = 0; k <= p1 - 1; k++)
                        {
                            if (toado[p1] < toado[k])
                            {
                                var tempImage = imgkytu[p1];
                                imgkytu[p1] = imgkytu[k];
                                imgkytu[k] = tempImage;
                                int temp = toado[p1];
                                toado[p1] = toado[k];
                                toado[k] = temp;
                            }
                        }
                        p1 += 1;
                    }
                    else
                    {
                        if (det.rect.X > 50 && det.rect.X < 100)
                        {
                            Part1 = GrayImage.Copy(det.rect).Resize(50, 50, Emgu.CV.CvEnum.INTER.CV_INTER_LINEAR);

                        }
                        else if (det.rect.X > 100 && det.rect.X < GrayImage.Width / 2)
                        {
                            Part2 = GrayImage.Copy(det.rect).Resize(50, 50, Emgu.CV.CvEnum.INTER.CV_INTER_LINEAR);
                        }
                        else if (det.rect.X > GrayImage.Width / 2 && det.rect.X < 300)
                        {
                            Part3 = GrayImage.Copy(det.rect).Resize(50, 50, Emgu.CV.CvEnum.INTER.CV_INTER_LINEAR);
                        }
                        else
                        {
                            Part4 = GrayImage.Copy(det.rect).Resize(50, 50, Emgu.CV.CvEnum.INTER.CV_INTER_LINEAR);
                        }
                    }
                }
            }
            string temp1 = "";
            string temp2 = "";
            string temp3 = "";
            string temp4 = "";
            string[] temp5 = new string[10];


            //chuyển thành tập SVM hợp lệ

            if (imgkytu != null)
            {
                for (int i = 0; i <= p1 - 1; i++)
                {
                    imgkytu[i]._Not();
                    strmucxam = imgkytu[i].GetAverage().ToString();
                    dblmucxam = Convert.ToDouble(strmucxam.Substring(1, strmucxam.Length - 2));
                    for (int m = 0; m <= 47; m++)
                    {
                        for (int n = 0; n <= 19; n++)
                        {
                            if (imgkytu[i][m, n].Intensity > dblmucxam)
                            {
                                temp5[i] += (m * imgkytu[i].Width + n + 1).ToString() + ":1 ";
                            }
                        }
                    }
                }
            }
            string result = "";
            if (Part1 != null)
            {
                Part1 = Part1.ThresholdBinary(new Gray(150), new Gray(255));
                Part1.SmoothMedian(3);
                hinh1.Image = Part1;
                double[] input = ImageProcessing.ToMatrix(Part1.Bitmap, Part1.Height, Part1.Width);
                string MatchedHigh = "?", MatchedLow = "?";
                double OutputValueHight = 0, OutputValueLow = 0;
                neuralNetwork.Recognize(input, ref MatchedHigh, ref OutputValueHight,
                               ref MatchedLow, ref OutputValueLow);
                result += MatchedHigh;
            }
            else
            {
                result += "_";
            }
            if (Part2 != null)
            {
                Part2 = Part2.ThresholdBinary(new Gray(150), new Gray(255));
                Part2.SmoothMedian(3);
                hinh2.Image = Part2;
                double[] input = ImageProcessing.ToMatrix(Part2.Bitmap, Part2.Height, Part2.Width);
                string MatchedHigh = "?", MatchedLow = "?";
                double OutputValueHight = 0, OutputValueLow = 0;
                neuralNetwork.Recognize(input, ref MatchedHigh, ref OutputValueHight,
                               ref MatchedLow, ref OutputValueLow);
                result += MatchedHigh;
            }
            else
            {
                result += "_";
            }
            result += "-";
            if (Part3 != null)
            {
                Part3 = Part3.ThresholdBinary(new Gray(150), new Gray(255));
                Part3.SmoothMedian(3);
                hinh3.Image = Part3;
                double[] input = ImageProcessing.ToMatrix(Part3.Bitmap, Part3.Height, Part3.Width);
                string MatchedHigh = "?", MatchedLow = "?";
                double OutputValueHight = 0, OutputValueLow = 0;
                neuralNetwork.Recognize(input, ref MatchedHigh, ref OutputValueHight,
                               ref MatchedLow, ref OutputValueLow);
                result += MatchedHigh;
            }
            else
            {
                result += "_";
            }
            if (Part4 != null)
            {
                Part4 = Part4.ThresholdBinary(new Gray(150), new Gray(255));
                Part4.SmoothMedian(3);
                hinh4.Image = Part4;
                double[] input = ImageProcessing.ToMatrix(Part4.Bitmap, Part4.Height, Part4.Width);
                string MatchedHigh = "?", MatchedLow = "?";
                double OutputValueHight = 0, OutputValueLow = 0;
                neuralNetwork.Recognize(input, ref MatchedHigh, ref OutputValueHight,
                               ref MatchedLow, ref OutputValueLow);
                result += MatchedHigh;
            }
            else
            {
                result += "_";
            }
            result += "-";
            return result.Trim();
        }
        
        private void Timer_Vao_Tick(object sender, EventArgs e)
        {
            //axLiveX1.StartGrapImage(true);
            biensoxevao = new Image<Bgr, Byte>(imgS);
            bienso = docbiensoForm(biensoxevao, picBiensovao);
            if (regex.IsMatch(bienso))
            {
                //axLiveX1.StartGrapImage(false);
                Timer_Vao.Enabled = false;               
                txtBiensovao.Text = bienso;
            }
            else
            {
                txtBiensovao.Text = bienso;
                // cbLoaixevao.SelectedItem = "Xe đạp";
            }
        }

        private void button3_Click(object sender, EventArgs e)
        {
            var FD = new SaveFileDialog();
            FD.Filter = "Network File(*.net)|*.net";
            if (FD.ShowDialog() == DialogResult.OK)
            {
                neuralNetwork.SaveNetwork(FD.FileName);
            }
            FD.Dispose();
        }
    }
}
